// $codepro.audit.disable spellCheckComments, spellCheckIdentifiers, spellCheckStringLiterals
/**
 * Package domain
 */
package teamrocket.domain; // $codepro.audit.disable packagePrefixNamingConvention

import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.logging.Level;

import teamrocket.db.DBWrapper;
import teamrocket.logging.TLogger;

/**
 * Represents an appointment with a doctor for a patient
 * @author Stephen
 *
 * @version $Revision: 1.0 $
 */
public class Appointment implements IDBObject<Appointment>{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;	// some comment
	
	/**
	 * Field date.
	 */
	private Date date;
	
	/**
	 * Field reason.
	 */
	private String reason;
	
	/**
	 * Field desiredDoctor.
	 */
	private int desiredDoctor;
	
	/**
	 * Field patientID.
	 */
	private int patientID;
	
	/**
	 * Field apptid.
	 */
	private int apptid;
	
	/**
	 * Creates an appointment with a certain doctor for a patient
	 * @param date
	 * @param reason
	
	 * @param desiredDoctor
	 * @param patientid int
	 */
	public Appointment(Date date, String reason, int patientid, int desiredDoctor) {
		this.date = date;
		this.reason = reason;
		this.desiredDoctor = desiredDoctor;
		this.patientID = patientid;
		TLogger.getInstance().getLogger().log(Level.INFO,
				"Creating new Appointment by Patient "
				+ patientID + " with Doctor "
				+ desiredDoctor
				+ " on " + date);
	}
	
	/**
	 * Method getDate.
	 * @return Date
	 */
	public Date getDate() {
		return date;
	}
	
	/**
	 * Method setDate.
	 * @param date Date
	 */
	public void setDate(Date date) {
		this.date = date;
	}
	
	/**
	 * Method getReason.
	 * @return String
	 */
	public String getReason() {
		return reason;
	}
	
	/**
	 * Method setReason.
	 * @param reason String
	 */
	public void setReason(String reason) {
		this.reason = reason;
	}
	
	/**
	 * Method getDesiredDoctor.
	 * @return int
	 */
	public int getDesiredDoctor() {
		return desiredDoctor;
	}
	
	/**
	 * Method setDesiredDoctor.
	 * @param desiredDoctor int
	 */
	public void setDesiredDoctor(int desiredDoctor) {
		this.desiredDoctor = desiredDoctor;
	}
	
	/**
	 * Method setPatient.
	 * @param patient int
	 */
	public void setPatient(int patient){
		this.patientID = patient;
	}
	
	/**
	 * Method getPatient.
	 * @return int
	 */
	public int getPatient(){
		return this.patientID;
	}
	
	/**
	 * Method getApptID.
	 * @return int
	 */
	public int getApptID(){
		return this.apptid;
	}
	
	/**
	 * Method setApptId.
	 * @param apptid int
	 */
	public void setApptId(int apptid){
		this.apptid = apptid;
	}
	
	/**
	 * Method create.
	 * @return IDBObject<Appointment>
	 * @see teamrocket.domain.IDBObject#create()
	 */
	
	@Override
	public IDBObject<Appointment> create(){
		try{
			try{
				DBWrapper.execute("INSERT INTO appointment " +
						"(patientid, doctorid, date, reason) VALUES (?,?,?,?)",
						this.patientID, 
						this.desiredDoctor, 
						this.date.getTime(), 
						this.reason);
				//Load the newly auto-generated appointment ID into the apptid field.  
				final ResultSet result = DBWrapper.query("SELECT id FROM " +
						"appointment WHERE patientid=(?) AND doctorid = (?) "
						+ "AND date=(?)", 
						this.patientID, 
						this.desiredDoctor, 
						this.date.getTime());
				
				// sees whether the collection is empty
				boolean empty = true;
				if(result != null){
					
					while(result.next()){ // $codepro.audit.disable nullPointerDereference
						empty = false;
						this.apptid = result.getInt("id");
					}
				}
				if(empty){
					throw new Exception("Cannot retrieve appointment ID"); // $codepro.audit.disable nullPointerDereference
				}
			} catch (SQLException e){
				e.printStackTrace();
			}
		}catch(Exception e){ 
			e.printStackTrace();
		}
		TLogger.getInstance().getLogger().log(Level.INFO,
				"Creating Appointment for Patient "
				+ patientID
				+ " on " + date);
		return this;
	}
	
	/**
	 * Method update.
	 * @see teamrocket.domain.IDBObject#update()
	 */
	@Override
	public void update(){
		try{
			DBWrapper.execute("UPDATE appointment SET " +
					"patientid = (?), doctorid = (?), date=(?), reason=(?)" +
					"WHERE id = (?)", 
					this.patientID, 
					this.desiredDoctor, 
					this.date.getTime(),
					this.reason, 
					this.apptid);
		}catch(SQLException e){
			e.printStackTrace();
		}
		TLogger.getInstance().getLogger().log(Level.INFO,
				"Updating Appointment for Patient "
				+ patientID
				+ " on " + date);
	}
	
	/**
	 * Method destroy.
	 * @see teamrocket.domain.IDBObject#destroy()
	 */
	@Override
	public void destroy(){
		try{
			DBWrapper.execute("DELETE FROM appointment WHERE id=(?)",
					this.apptid);
		}catch(SQLException e){
			e.printStackTrace();
		}
		TLogger.getInstance().getLogger().log(Level.INFO,
				"Destroying Appointment for Patient "
				+ patientID
				+ " on " + date);
	}
	
	/**
	 * Gets a list of appointments from the database
	
	 * @return Collection<Appointment>
	 */
	public static Collection<Appointment> getAppointments(){
		final Collection<Appointment> appointments = new ArrayList<Appointment>();
		try {
			final ResultSet rs = DBWrapper.query("SELECT * FROM appointment");
			while(rs.next()){ // $codepro.audit.disable nullPointerDereference
				Appointment toAdd = new Appointment(
						new Date(rs.getLong("date")),
						rs.getString("reason"),
						rs.getInt("patientid"),
						rs.getInt("doctorid"));
				toAdd.setApptId(rs.getInt("id"));
				appointments.add(toAdd);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		TLogger.getInstance().getLogger().log(Level.INFO, "Got Appointments.");
		return appointments;
	}
	
	/**
	 * Method getAppointments.
	 * @param patientid int
	 * @return Collection<Appointment>
	 */
	public static Collection<Appointment> getAppointments(int patientid){
		// check for negative patientid
		final Collection<Appointment> appointments = new ArrayList<Appointment>();
		try {
			final ResultSet rs = DBWrapper.query("SELECT * FROM " +
					"appointment WHERE patientid = ?", patientid);
			while(rs.next()){ // $codepro.audit.disable nullPointerDereference
				Appointment toAdd = new Appointment(
						new Date(rs.getLong("date")),
						rs.getString("reason"),
						rs.getInt("patientid"),
						rs.getInt("doctorid"));
				toAdd.setApptId(rs.getInt("id"));
				appointments.add(toAdd);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		TLogger.getInstance().getLogger().log(Level.INFO, "Got Appointments.");
		return appointments;
	}
	
	/**
	 * Method getAppointmentsAtDate gets all the appointments in the given date.
	 * @param date <!-- // $codepro.audit.disable methodJavadoc -->
	 * @return Collection<Appointment>
	 */
	public static Collection<Appointment> getAppointmentsAtDate(Date dt){ // $codepro.audit.disable methodJavadoc
		// check for negative patientid
		final Collection<Appointment> appointments = new ArrayList<Appointment>();
		
		//Getting initial range date
		final Calendar cal = Calendar.getInstance();
		cal.setTime(dt);
		final int day = cal.get(Calendar.DATE);
		final int month = cal.get(Calendar.MONTH);
		final int year = cal.get(Calendar.YEAR);
		
		final Calendar calInitial = Calendar.getInstance();
		//Set beginning of day
		calInitial.set(year, month, day, 0, 0, 0);
		final Date dtInitial = calInitial.getTime();
		final long dateInitial = dtInitial.getTime();
		//Set ending of day
		calInitial.set(year, month, day, 23, 59, 60); // $codepro.audit.disable numericLiterals
		final Date dtFinal = calInitial.getTime();
		final long dateFinal = dtFinal.getTime();
		try {
			final ResultSet rs = DBWrapper.query("SELECT * FROM " +
					"appointment WHERE date between(?) AND (?)", dateInitial, dateFinal);
			while(rs.next()){
				Appointment toAdd = new Appointment(
						new Date(rs.getLong("date")),
						rs.getString("reason"),
						rs.getInt("patientid"),
						rs.getInt("doctorid"));
				toAdd.setApptId(rs.getInt("id"));
				appointments.add(toAdd);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		TLogger.getInstance().getLogger().log(Level.INFO, "Got Appointments.");
		return appointments;
	}
	
	/**
	 * Method toString.
	 * @return String
	 */
	@Override
	public String toString(){
		return date.toString() + " - " +  reason;
	}
}
